/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package percussiongenerator.model;

import percussiongenerator.sound.ITimeListener;
import javax.sound.midi.Instrument;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.basics.Node;
import org.jfonia.connect5.basics.Observer;
import org.jfonia.constants.SymbolConstants;
import org.jfonia.model.PerformanceNode;
import org.jfonia.model.Sequence;
import org.jfonia.model.Staff;
import org.jfonia.model.TempoMap;
import org.jfonia.model.TempoNode;
import org.jfonia.model.ToneSequence;
import org.jfonia.model.elements.TimeSignature;
import org.jfonia.model.elements.Tone;
import percussiongenerator.sound.DrumkitHelp;
import percussiongenerator.sound.SimpleInstrument;

/**
 *
 * @author Jannes Plyson
 */
public class Track implements ITimeListener,Observer{

    private Staff staff;
    private MutableValueNode<SimpleInstrument> instrumentNode;
    private MutableValueNode<Long> timeNode;
    private boolean mute;
    private TrackCollection trackCollection;

    public Track(Staff staff){        
        this.staff = staff;
        instrumentNode = new BasicValueNode<SimpleInstrument>(new SimpleInstrument(null));
        timeNode = new BasicValueNode<Long>(0l);
        trackCollection = null;
        instrumentNode.addObserver(this);
    }

    public void shift(long time){

    }

    public void shift(int ticks){

    }

    public long getTime(){
        return timeNode.getValue();
    }

    public MutableValueNode<Long> getTimeNode(){
        return timeNode;
    }

    public boolean isMuted(){
        return mute;
    }

    public void setMute(boolean mute){        
        this.mute = mute;
        updateTrackCollection();        
    }    

    //TODO remove this function, currently used for quantisation.
    public Staff getStaff(){
        return staff;
    }

    public SimpleInstrument getInstrument(){
        return instrumentNode.getValue();
    }

    public MutableValueNode<SimpleInstrument> getInstrumentNode(){
        return instrumentNode;
    }

    public TrackCollection getTrackCollection(){
        return trackCollection;
    }

    public void setTrackCollection(TrackCollection trackCollection){
        this.trackCollection = trackCollection;
    }    

    public void removeFromCollection(){
        if(trackCollection != null){
            trackCollection.removeTrack(this);
        }
    }

    public void setInstrument(SimpleInstrument instrument){
        instrumentNode.setValue(instrument);
        updateTrackCollection();
    }

    private void updateTrackCollection(){
        if(trackCollection != null){
            trackCollection.trackUpdated(this);
        }
    }

    public void timeUpdated(long time) {
        timeNode.setValue(time%getPerformanceLength());
    }

    public long getPerformanceLength(){
        ToneSequence seq = staff.getToneSequence();
        if(seq != null){
            return seq.getPerformanceLength();
        }else{
            return 1l;
        }
    }

    public void onNotify(Object source) {
        updateTrackCollection();
    }

    public static Track createMetronome(Instrument instrument, int bpm){
        long duration = 60000000000l/bpm;
        PerformanceNode pn = new PerformanceNode(duration);
        pn.setPitch(DrumkitHelp.getPitch("Low Wood Block"));
        pn.setVelocity(80);

        //PerformanceNode pn2 = new PerformanceNode(duration);
        //pn2.setPitch(DrumkitHelp.getPitch("Low Wood Block"));
        //pn2.setVelocity(120);
        ToneSequence seq = new ToneSequence();
        seq.add(pn);
        //seq.add(pn2);
        seq.setLockNotation(false);
        Staff staff = new Staff();
        TempoMap tempoMap = new TempoMap();
        TempoNode tn = new TempoNode();
        tn.setBPM(bpm);
        tempoMap.add(tn);
        staff.setTempoMap(tempoMap);
        staff.addSequence(seq);
        TimeSignature ts = (TimeSignature)staff.getSequence(TimeSignature.class).getIntervalFromIndex(0);       
        staff.getQuantizerNode().getQuantizer().setSmallestValue(SymbolConstants.DIVISOR/ts.getDenominator());
        for(int i = 1; i < ts.getDenominator(); i++){
            seq.add(pn.clone());
        }
        ((PerformanceNode)staff.getToneSequence().getPerformanceSequence().getIntervalFromIndex(0)).setVelocity(120);
        Track track = new Track(staff);
        track.setInstrument(new SimpleInstrument(instrument,DrumkitHelp.getPitch("Low Wood Block")));
        return track;
    }
}
